/***************************************************************************
 *            obj_model.c
 *
 *  Sat Sep  6 20:51:53 2008
 *  Copyright  2008  Tiago Falcão
 *  <tiago@tiagofalcao.com>
 ****************************************************************************/

/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Library General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor Boston, MA 02110-1301,  USA
 */
#include "obj_model.h" 

#define ALLOC_F_GAP 600
#define ALLOC_V_GAP 200

//Carrega Estrutura de arquivo OBJ
obj_model * obj_model_load(char * file){
	char type;
	float x,y,z;
	
	unsigned int v_size=0,f_size=0;
	obj_model * model=malloc(sizeof(obj_model));		//Aloca Estrutura
	
	model->v_size=ALLOC_V_GAP;							//Aloca Vetor inicial para Vertices
	model->v=malloc(model->v_size*sizeof(GLfloat *));
	
	model->f_size=ALLOC_F_GAP;							//Aloca Vetores iniciais para Faces
	model->f=malloc(model->f_size*sizeof(GLfloat **));
	model->fn=malloc(model->f_size*sizeof(GLfloat *));
	
	 
	FILE * arq=fopen(file,"r");							//Abre Arquivo
	while(fscanf(arq,"%c %f %f %f\n",&type,&x,&y,&z)==4){
	 switch(type){
		 case 'v':{										//Vertice
			 model->v[v_size]=calloc(6,sizeof(GLfloat));//Aloca espaco para Vertice e Normal
			 model->v[v_size][0]=x;
			 model->v[v_size][1]=y;
			 model->v[v_size][2]=z;
			 if(++v_size==model->v_size){				//Se lotar o vetor realoca mais espaço
				 model->v_size+=ALLOC_V_GAP;
				 model->v=realloc(model->v,model->v_size*sizeof(GLfloat *));
			 }
			 break;
		 }
		 case 'f':{										//Face
			 int xi=x-1,yi=y-1,zi=z-1;
			 GLfloat d1[3], d2[3];
			 
			 model->f[f_size]=calloc(3,sizeof(GLfloat*));//Aloca espaco para Face
			 model->f[f_size][0]=model->v[xi];			//Vertices da Face
			 model->f[f_size][1]=model->v[yi];
			 model->f[f_size][2]=model->v[zi];
			 
			 /*if(det(model->f[f_size][0],model->f[f_size][1],model->f[f_size][2])<0){//Confere Determinante da Face
				 GLfloat * swap=model->f[f_size][1];								//e corrige
				 model->f[f_size][1]=model->f[f_size][2];
				 model->f[f_size][2]=swap;
			 }*/
			 
			 model->fn[f_size]=calloc(3,sizeof(GLfloat));					//Aloca Espaco para a normal da Face
			 for (xi = 0; xi < 3; xi++) {    
				d1[xi] = model->f[f_size][0][xi] - model->f[f_size][1][xi];    
				d2[xi] = model->f[f_size][1][xi] - model->f[f_size][2][xi];    
			 }
			 normcrossprod(d1, d2, model->fn[f_size]);
			 
		     for(yi=0;yi<3;yi++){								//Calcula Normais dos Vertices Participantes
				 for(zi=0;zi<3;zi++)
					 model->f[f_size][yi][zi+3]+=model->fn[f_size][zi];
				 normalize(&(model->f[f_size][yi][3]));
			 }
			 
			 if(++f_size==model->f_size){						//Aloca mais espaco se necessario
				 model->f_size+=ALLOC_F_GAP;
				 model->f=realloc(model->f,model->f_size*sizeof(GLfloat **));
				 model->fn=realloc(model->fn,model->f_size*sizeof(GLfloat *));
			 }
			 break;
		 }
	 }
	}
	fclose(arq);
	if(v_size<model->v_size){			//Corrige Comprimento do Vetor de Vertices
		model->v_size=v_size;
		model->v=realloc(model->v,model->v_size*sizeof(point_cart));
	}
	if(f_size<model->f_size){			//Corrige Comprimento do Vetor de Faces
		model->f_size=f_size;
		model->f=realloc(model->f,model->f_size*sizeof(point_cart));
	}
	 return model;
}

//Deleta Estrutura
void obj_model_delete(void * ptr){
	obj_model * obj=(obj_model *)ptr;
	int i;
	for(i=0;i<obj->f_size;i++){		//Libera as Faces
		free(obj->f[i]);
		free(obj->fn[i]);
	}
	if(obj->f_size){				//Libera Vetor de Faces
		free(obj->f);
		free(obj->fn);
	}
	for(i=0;i<obj->v_size;i++)		//Libera Vertices
		free(obj->v[i]);
	if(obj->v_size)					//Libera Vetor de Vertices
		free(obj->v);
	free(obj);
}

//Display de Modelo de Malha Triangular
void obj_model_display(void * model,bool flat,GLuint texture){
	obj_model * obj=(obj_model *)model;

	if(texture){								//Texture
		glEnable(GL_TEXTURE_2D); 
		glEnable(GL_TEXTURE_GEN_S);
		glEnable(GL_TEXTURE_GEN_T);
		glBindTexture(GL_TEXTURE_2D, texture);
	}
	if(!flat){				//Modo Smooth
		int i;
		glBegin(GL_TRIANGLES);
			for(i=0;i<obj->f_size;i++){
				glNormal3fv(&(obj->f[i][0][3]));
				glVertex3fv(obj->f[i][0]);
				glNormal3fv(&(obj->f[i][1][3]));
				glVertex3fv(obj->f[i][1]);
				glNormal3fv(&(obj->f[i][2][3]));
				glVertex3fv(obj->f[i][2]);
			}
		glEnd(); 
	}else{										//Modo Flat
		int i;
		glShadeModel(GL_FLAT);
		glBegin(GL_TRIANGLES);
			for(i=0;i<obj->f_size;i++){
				glNormal3fv(obj->fn[i]);
				glVertex3fv(obj->f[i][0]);
				glVertex3fv(obj->f[i][1]);
				glVertex3fv(obj->f[i][2]);
			}
		glEnd();
		glShadeModel(GL_SMOOTH);
	}
	if(texture){								//End Texture
		glDisable(GL_TEXTURE_2D);
		glDisable(GL_TEXTURE_GEN_S);
		glDisable(GL_TEXTURE_GEN_T);
	}
}

